﻿namespace CookieTerm
{
    using System;

    public struct ConsoleCell
    {
        public int Columns;
        public int Row;
        public int Column;

        public ConsoleCell(int columns, int row, int column)
        {
            this.Columns = columns;
            this.Row = row;
            this.Column = column;
        }

        public static ConsoleCell operator ++(ConsoleCell p)
        {
            ConsoleCell result = p;
            result.Column++;
            if (result.Column > result.Columns)
            {
                result.Column = 1;
                result.Row++;
            }

            return result;
        }

        // The following comparison operators assume the points have the same
        // number of columns
        public static bool operator <(ConsoleCell p1, ConsoleCell p2)
        {
            ThrowIfDimensionsDiffer(p1, p2);
            return p1.Cardinal() < p2.Cardinal();
        }

        public static bool operator >(ConsoleCell p1, ConsoleCell p2)
        {
            ThrowIfDimensionsDiffer(p1, p2);
            return !(p1 <= p2);
        }

        public static bool operator ==(ConsoleCell p1, ConsoleCell p2)
        {
            ThrowIfDimensionsDiffer(p1, p2);
            return p1.Column == p2.Column && p1.Row == p2.Row;
        }

        public static bool operator !=(ConsoleCell p1, ConsoleCell p2)
        {
            return !(p1 == p2);
        }

        public static bool operator <=(ConsoleCell p1, ConsoleCell p2)
        {
            return p1 == p2 || p1 < p2;
        }

        public static bool operator >=(ConsoleCell p1, ConsoleCell p2)
        {
            return p1 == p2 || p1 > p2;
        }

        public static ConsoleCell Min(ConsoleCell p1, ConsoleCell p2)
        {
            return p1 < p2 ? p1 : p2;
        }

        public static ConsoleCell Max(ConsoleCell p1, ConsoleCell p2)
        {
            return p1 < p2 ? p2 : p1;
        }

        public int Cardinal()
        {
            return this.Column + (this.Row * this.Columns);
        }

        public override bool Equals(object obj)
        {
            return this == (ConsoleCell)obj;
        }

        public override int GetHashCode()
        {
            return this.Cardinal();
        }

        private static void ThrowIfDimensionsDiffer(ConsoleCell p1, ConsoleCell p2)
        {
            if (p1.Columns != p2.Columns)
            {
                throw new ArgumentException("Cannot compare two cells with different columns.");
            }
        }
    }
}
